/*
 * Title: WADS
 * Description: Web-based Auto flow Documents System
 * Copyright: 2007
 * Company: CoE
 * @author: Old developer team
 * @version 1.1
 */

package wads.app;

import sandbox.WadsConfigDialog;
import wads.app.control.WADSXMLExporter;
import wads.drawing.line.CaseLink;
import wads.drawing.node.DocumentNode;
import wads.drawing.node.DatabaseNode;
import wads.drawing.node.CaseNode;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.BufferedWriter;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import wads.app.control.WADSXMLImporter;
import wads.com.DocumentTemplateInfo;
import wads.com.WADTools;
import wads.drawing.CaseShape;
import wads.drawing.node.UserNode;

public class WADDiagramEditor extends CaseEditor {

  private Properties properties;
  private WADConfigDialog configDialog;
  private WadsConfigDialog configDialog1;
  private String org;
  //private boolean check = true;
  private UserManagerFrame umf;

  /**
   * @param org_name Organization file name. Use to tell system which Organization file will use.
   */
  public WADDiagramEditor(String org_name) {
    super("WADS 1.1");
    org = org_name;
    
    //initUI() is method from CaseEditor
    initUI(new WADDiagramToolBar(this), new WADDiagramPanel(this));

    //drawPanel is variable from CaseEditor.
    //declare to be object from DrawPanel Class
    //this command below is for draw DocumentNode Shape first
    //when user start program.
    drawPanel.addDocShape(new DocumentNode(new Point(80, 50)));

    //load properties from config file
    properties = WADTools.loadWadConfig();
    File configFile = new File(WADTools.CONFIG_FILENAME);
//    try {
//      configFile = new File(WADTools.CONFIG_FILENAME);
//      if(configFile.exists()){
//        properties.load(new FileInputStream(configFile));
//      }
//      else {
//        //set default properties
//        properties.setProperty(WADTools.LAST_TEMPLATE_ID_KEYNAME, String.valueOf(WADTools.LAST_TEMPLATE_ID_DEFAULT));
//        properties.setProperty(WADTools.SERVER_NAME_KEYNAME, WADTools.SERVER_NAME_DEFAULT);
//        properties.setProperty(WADTools.ACTION_NAME_KEYNAME, WADTools.ACTION_NAME_DEFAULT);
//        properties.store(new FileOutputStream(configFile), "");
//      }
//    }
//    catch(Exception e) { System.out.println("Config file error"); }

    //set Org to properties
    try{
      if(!this.org.equals("Untitled1"))
        properties.setProperty("orgName", this.org);
      else
        properties.setProperty("orgName", this.org);

      properties.store(new FileOutputStream(configFile), "Update Org to config file.");
      WADTools.initialSharingResource();
    }
    catch(Exception e){ e.printStackTrace(); }

    //Edit WAD Menu here: add and set all Menu Item of WAD Menu
    JMenuBar jmb = this.getJMenuBar();
    JMenu wad_menu = jmb.getMenu(3);

    JMenuItem manageOrgItem = new JMenuItem("Organization Manager", new ImageIcon("images/nullicon.gif"));
    manageOrgItem.addActionListener(new ManageAction(this, this.org));
//    manageOrgItem.setFont(LABEL_FONT);
    manageOrgItem.setEnabled(true);
    wad_menu.add(manageOrgItem);

    JMenuItem configItem = new JMenuItem("Configuration", new ImageIcon("images/nullicon.gif"));
    configItem.addActionListener(new ConfigAction(properties, configFile, this));
//    configItem.setFont(LABEL_FONT);
    configItem.setEnabled(true);
    wad_menu.add(configItem);

    wad_menu.addSeparator();  // Add Separator Line

    JMenuItem activateItem = new JMenuItem("Export Template", new ImageIcon("images/import.gif"));
    activateItem.addActionListener(new ActivateAction(this.drawPanel.getShapeDrawn()));
//    activateItem.setFont(LABEL_FONT);
    activateItem.setEnabled(true);
    wad_menu.add(activateItem);

    JMenuItem importItem = new JMenuItem("Import Template");
    importItem.addActionListener(new ImportAction());
    importItem.setEnabled(true);
    wad_menu.add(importItem);

    JMenuItem deActivateItem = new JMenuItem("Remove Template", new ImageIcon("images/export.gif"));
    deActivateItem.addActionListener(new DeActivateAction());
//    deActivateItem.setFont(LABEL_FONT);
    deActivateItem.setEnabled(true);
    deActivateItem.setVisible(false);
    wad_menu.add(deActivateItem);
    
    this.setSize(800, 600);
    //this.setExtendedState(JFrame.MAXIMIZED_BOTH);
  }//end of WADDiagramEditor()

  protected class ConfigAction extends AbstractAction {
    private Properties prop;
    private File configFile;
    private WADDiagramEditor owner;

    public ConfigAction(Properties config_prop, File confFile, WADDiagramEditor config_owner){
      this.prop = config_prop;
      this.configFile = confFile;
      this.owner = config_owner;
    }

    @Override
    public void actionPerformed(ActionEvent evt) {
      if(configDialog == null)
        configDialog = new WADConfigDialog(this.owner, true);
       //else {
        //may show dialog to display and allow user to edit this properities
        //don't forget to store the properties after changing
        //configDialog1.setConfigProps(prop);
      configDialog.loadPropertiesToDialog(prop);
      configDialog.setVisible(true);
    }
    
    public File getConfigFile(){
      return configFile;
    }
  }//end of ConfigAction Class

  protected class ManageAction extends AbstractAction {
    protected WADDiagramEditor owner;
    private String org;

    public ManageAction(WADDiagramEditor owner,String org){
      this.owner = owner;
      this.org = org;
      if(false)
        System.out.println(this.org);
    }

    @Override
    public void actionPerformed(ActionEvent evt) {
        if(getDb().isDbServerOn()) {
            umf = new UserManagerFrame(this.owner , this.org);
            umf.setVisible(true);
            //umf = new UMFrame();
            //umf.setVisible(true);
        }
        else {
            JOptionPane.showMessageDialog(rootPane, "Cannot connect to the Database server.", "Connecting Error",
                    JOptionPane.ERROR_MESSAGE);
        }
    }
  }//end of ManageAction Class

  protected class ActivateAction extends AbstractAction {
//    private static final long serialVersionUID = -75573511920123910L;
    
    private Vector shapesDrawn;

    public ActivateAction(Vector shapes) {
      this.shapesDrawn = shapes;
    }

    /**
     * @param htmlFile HTML template file name to be saved.
     * @param action HTML Action, set for tell HTML Form tag know where to go when action performed.
     * @param templateID
     * @param templateName
     * @return If all works done successfully return true.
     */
    private boolean updateHTML(File htmlFile, String action, String templateID, String templateName) {
      //this method can't call more than one
      String temp = null;
      String temp1 = null;
      String readData = "";
      int actionIndex = 0;
      int equalIndex = 0;
      boolean flag = false;
      boolean found = false;
      String hiddenID = "<input type=\"hidden\" name=\"template_ID\" value=\"" + templateID + "\">";
      String hiddenName = "<input type=\"hidden\" name=\"template_Name\" value=\"" + templateName + "\">";

      OutputStreamWriter osw;
      InputStreamReader isr;

      try{
        /**
         * old version (1.0) use DataInputStream.readLine(); to read file data
         * but it predicated by JDK 1.4 and suggested to replace with BufferedReader.readLine();
         * But if you just only replace DataInputStream with BufferedReader,
         * with old source code that have FileInputStream + DataOutputStream
         * it won't work with Thai character.
         * So I change the way to read FILE and it can work with Thai font properly.
         * I use FileReader and FileWriter replace FileInputStream, DataInputStream,
         * and DataOutputStream.
         * -----
         * Update 2007-09-25:
         * Make IO Read/Write with specify "Character Encoding" (UTF-8).
         * Because output HTML files with no Charset specified
         * will have some illegal result when display.
         */
        File outFile = new File(htmlFile.getParent() + "/" + templateID + ".html");
        osw = new OutputStreamWriter(new FileOutputStream(outFile, false), "UTF-8");  //make file use overwritten method.
        BufferedWriter bw = new BufferedWriter(osw);
        
        isr = new InputStreamReader(new FileInputStream(htmlFile), "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        //fw = new FileWriter(outFile); @deprecate Use OutputStreamWriter instead.
        //Loop to copy HTML all texts to new HTML form template
        while((temp = br.readLine()) != null){
          //find "action" for fill action target in action=""
          if((actionIndex = temp.indexOf("action")) != -1){
            temp1 = temp.substring(actionIndex+6);
            equalIndex = temp1.indexOf("\"");
            temp1 = temp1.substring(0,equalIndex+1) + action + temp1.substring(equalIndex+1);
            temp = temp.substring(0, actionIndex+6);
            temp = temp + temp1;
            flag = true;
            found = true;
              System.out.println("found Action field of HTML Form...");
          }
          readData = readData + temp + "\n";

          //when found "action" tag fill these 2 hidden tags
          if(flag){
            readData = readData + hiddenID + "\n";
            readData = readData + hiddenName + "\n";
            flag = false;
          }
        }

        bw.write(readData);

        br.close();
        bw.close();
        isr.close();
        osw.close();
        htmlFile.delete();
      }
      catch(Exception e) {
        System.err.println("Exception thrown from WADDiagramEditor.ActivateAction.updateHTML() while try to read HTML data from file.");
        e.printStackTrace();
      }

        System.out.println("Update file: " + htmlFile.getPath());
      return found;
    } // end of UpdateHTML()

    @Override
    public void actionPerformed(ActionEvent evt) {
      WADSXMLExporter diagramParser = new WADSXMLExporter(drawPanel.getShapeDrawn());
      diagramParser.createDocument();
      //diagramParser.exportXMLFile(new File("res/test/test.xpdl"));
      String template_ID;
      String template_Name;
      String template_Source;
      boolean canActivate = true;
      int tID = 0;
      Properties p = new Properties();

      try {
        //find the appropriate document template ID
        p.load(new FileInputStream(WADTools.CONFIG_FILENAME));
        tID = Integer.parseInt(p.getProperty(WADTools.LAST_TEMPLATE_ID_KEYNAME, String.valueOf(WADTools.LAST_TEMPLATE_ID_DEFAULT)));
        template_ID = WADTools.int2ConstLenString(tID, WADTools.TEMPLATE_ID_LEN);

        //check for unique template_ID
        while((new File(WADTools.ACTIVATE_DIR_PATH + template_ID)).exists()) {
          tID++;
          template_ID = WADTools.int2ConstLenString(tID, WADTools.TEMPLATE_ID_LEN);
        }
      }
      catch(FileNotFoundException fnfx) {
          System.err.println("Can't find configuration file.");
        fnfx.printStackTrace();
        return;
      }
      catch(IOException iox) {
          System.err.println("IOException found.");
        iox.printStackTrace();
        return;
      }
      catch(Exception e) {
          System.err.println("Cannot activate document template.");
        e.printStackTrace();
        return;
      } // end of try-catch:find lastest blank templateID, found templateID to use.

      //Search for the START of the flow -- DocumentNode
      DocumentNode doc_head_of_flow = null;
      Enumeration en = shapesDrawn.elements();
      while(en.hasMoreElements()) {
        Object obj = en.nextElement();
        if(obj instanceof DocumentNode){
          doc_head_of_flow = (DocumentNode)obj;
        }
      }

//      template_Name = doc_head_of_flow.getDocProp().getProperty(DocumentNode.DOCUMENT_NAME_KEYNAME, "");
//      template_Source = doc_head_of_flow.getDocProp().getProperty(DocumentNode.DOCUMENT_PATH_KEYNAME, "");
      template_Name = doc_head_of_flow.getName();
      template_Source = doc_head_of_flow.getPrototypePath();

      //check template source
      try {
        File tsFile = new File(template_Source);
        if(!tsFile.exists())
          template_Source = null;
      }
      catch(Exception e) {
        template_Source = null;
      }

      if(template_Source == null) {
        JOptionPane.showMessageDialog(WADDiagramEditor.this,
          "Source of document template isn't available.",
          "Alert", JOptionPane.ERROR_MESSAGE);
          System.out.println("HTML source file selected is unavailable.");
        return;
      }

      //ready to create document template info object to save
      DocumentTemplateInfo dtInfo = new DocumentTemplateInfo(template_ID, template_Name);

      CaseNode currentNode = null, nextNode = null;
      CaseLink outLink;
      
      System.out.println(doc_head_of_flow.getConnectedLinksSize());

      if(doc_head_of_flow != null && doc_head_of_flow.getConnectedLinksSize()== 1){
        //the head_of_flow is valid -- in term of diagram connection
        nextNode = (CaseNode)doc_head_of_flow;

        do{
          currentNode = nextNode;
          //finding outLink
          outLink = null;
          Enumeration enum_link = currentNode.getConnectedLinks().elements();
          while(enum_link.hasMoreElements()){
            CaseLink link = (CaseLink)enum_link.nextElement();

            if(link.getStartNode().equals(currentNode)){
              outLink = link;
              break;
            }
          }

          if(currentNode instanceof UserNode){
            String userName = ((UserNode)currentNode).getName();
            // **** it's  better if can check the username with the organization info ****
            if(userName != null && !userName.equals(""))
              dtInfo.add_nextUser_to_Flow(userName);
          }
          else if(currentNode instanceof DatabaseNode){
            //need to save any transaction which derive this document template to database
            dtInfo.setNeed_SaveToDB(true);
          }

          if(outLink != null)
            nextNode = outLink.getEndNode();

        }while(outLink != null);

      }
      else
        canActivate = false;

      if(!canActivate) {
        JOptionPane.showMessageDialog(WADDiagramEditor.this,
          "Flow verification isn't successful.. cancel activating",
          "Alert", JOptionPane.ERROR_MESSAGE);
          System.out.println("Flow diagram is incorrect form activating canceled.");
        return;
      }
      else {
      //activate the document template
        try {
          File srcFile = new File(template_Source);
          File dstFile = new File(WADTools.ACTIVATE_DIR_PATH + template_ID);
          WADTools.copyDir(srcFile.getParentFile(), dstFile);

          //String actionURL = p.getProperty(WADTools.SERVER_NAME_KEYNAME, WADTools.SERVER_NAME_DEFAULT) +
          //p.getProperty(WADTools.ACTION_NAME_KEYNAME, WADTools.ACTION_NAME_DEFAULT);
          String actionURL = "../submitForm";
          
          System.out.println(p.getProperty(WADTools.SERVER_NAME_KEYNAME, WADTools.SERVER_NAME_DEFAULT));
          System.out.println(p.getProperty(WADTools.ACTION_NAME_KEYNAME, WADTools.ACTION_NAME_DEFAULT));

          updateHTML(new File(WADTools.ACTIVATE_DIR_PATH + template_ID + "/" + srcFile.getName()), actionURL, template_ID, template_Name);

          ObjectOutputStream oos = new ObjectOutputStream(
            new FileOutputStream(WADTools.ACTIVATE_DIR_PATH + template_ID + "/" + WADTools.DOC_TEMPLATE_INFO_FILENAME));
          //ObjectOutputStream xos = new ObjectOutputStream(new FileOutputStream(WADTools.ACTIVATE_DIR_PATH+template_ID+"/"+template_ID+".xpdl"));
          File xpdl = new File(WADTools.ACTIVATE_DIR_PATH+template_ID+"/"+template_ID+".xpdl");
          diagramParser.exportXMLFile(xpdl);

          oos.writeObject(dtInfo);
          oos.close();

          System.out.println("Activate template document ("+dtInfo.getTemplate_ID()+", "+dtInfo.getTemplate_Name()+")");

          p.setProperty(WADTools.LAST_TEMPLATE_ID_KEYNAME, String.valueOf(tID + 1));
          p.store(new FileOutputStream(WADTools.CONFIG_FILENAME), "");
          WADTools.initialSharingResource();
          
          JOptionPane.showMessageDialog(WADDiagramEditor.this, "Export Template Document Succeed",
              "Export Succeed", JOptionPane.INFORMATION_MESSAGE);
          System.out.println("Export template document succeed.");

        }
        catch(Exception e) {
          System.err.println("Exception thrown from WADDiagramEditor.ActivateAction.actionPerformed() while document template export activating.");
          e.printStackTrace();
        }
      }
    }//end of ActionPerformed()
  }//end of ActivateAction Class

  protected class ImportAction extends AbstractAction {

      @Override
      public void actionPerformed(ActionEvent e) {
          WADSXMLImporter importer = new WADSXMLImporter(getPUUserInfo());
          JFileChooser chooser = new JFileChooser("res/docs/activeDocTemplate");
          FileNameExtensionFilter filter = new FileNameExtensionFilter("XML Process Definition Language file.", "xpdl");
          chooser.setFileFilter(filter);
          chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
          chooser.setMultiSelectionEnabled(false);
          if(chooser.showOpenDialog(WADDiagramEditor.this)==JFileChooser.APPROVE_OPTION) {
              Vector<CaseShape> drawnobject = importer.importXMLFile(chooser.getSelectedFile());
              WADDiagramEditor.this.getDrawPanel().setShapesDrawn(drawnobject);
          }
      }
  }

  protected class DeActivateAction extends AbstractAction {
//    private static final long serialVersionUID = 2291879795783134730L;
    private DeActivateDTDialog deActivateDTDialog;
    private Vector<DocumentTemplateInfo> documentVector;

    public DeActivateAction() {
      documentVector = new Vector<DocumentTemplateInfo>();
    }

    /* (non-Javadoc)
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    @Override
    public void actionPerformed(ActionEvent evt) {
      documentVector.clear();
      String data = null;
      //example... list all of activated documents
      try {
        File aDir = new File(WADTools.ACTIVATE_DIR_PATH);
        File[] aDirList = aDir.listFiles();
        for(int i = 0; i < aDirList.length; i++) {
          if(aDirList[i].isDirectory() && !aDirList[i].getName().equals(".svn")) {
            System.out.println(aDirList[i].getName());
            //found the activated document template
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(aDirList[i].getAbsolutePath() + "/" + WADTools.DOC_TEMPLATE_INFO_FILENAME));
            DocumentTemplateInfo dtInfo = (DocumentTemplateInfo)ois.readObject();
            ois.close();

            data = dtInfo.getTemplate_ID() + " : " + dtInfo.getTemplate_Name() + " : " +
              dtInfo.getCreated_Date().toString();

            System.out.print(data);
            documentVector.add(dtInfo);

            //example for finding the flow
            String usr = dtInfo.getFirstUser();
            if(usr != null){
              String flow = " @ " + usr;
              while((usr = dtInfo.whois_nextUser_from_thisUser(usr)) != null)
                flow += " -> " + usr;
              System.out.println(flow);
            }
          }
        }
      }
      catch(Exception e) {
        System.err.println("Exception thrown from WADDiagramEditor.DeActivateAction.actionPerformed() while reading document template file.");
        e.printStackTrace();
      }

      if(deActivateDTDialog == null)
        deActivateDTDialog = new DeActivateDTDialog(WADDiagramEditor.this, documentVector);
      else
        deActivateDTDialog.initDisplay();

      deActivateDTDialog.setModal(true);
      deActivateDTDialog.setVisible(true);
    }//end of ActionPerformed()
  }//end of DeActivateAction Class

  /**
   * @return Return current Organization file name that program using.
   */
  public String getOrgName(){
    return org;
  }
}//end of WADDiagramEditor Class